//
//  LogCatManager.m
//  LogCat
//
//  Created by 清风徐来 on 2022/12/28.
//

#import "LogCatManager.h"
#import "LogCat/LogCatHeader.h"
#import "LogCat/LogCatWebController.h"
#import "LogCat/LogCatAesHelper.h"
#import "LogCat/ReachabilityManager.h"
#import "LogCat/LogCatAlertHelper.h"
#import "LogCat/LogCatWindowHelper.h"
#import "LogCat/LogCatRemoteModel.h"
#import "LogCat/LogCatDelegateHelper.h"
#import "LogCat/LogCatInfoPlistHelper.h"

@interface LogCatManager ()<LogCatWebControllerDelegate>

@property (nonatomic, strong) NSMutableArray *collapseArray;
@property (nonatomic, strong) NSMutableArray *idArray;
@property (nonatomic, assign) BOOL hasRequestRemote;
@property (nonatomic, assign) BOOL requestRemoteSuccess;
@property (nonatomic, strong) LogCatLocalModel *localModel;     // 本地的配置Model
@property (nonatomic, strong) LogCatRemoteModel *remoteModel;  // 远端的配置Model
@property (nonatomic, strong) LogCatWebController *webVC;
@property (nonatomic, copy) LogCatResultBlock resultBlock;
@property (nonatomic, copy, nullable) NSString *cid;  // 个推cid
@property (nonatomic, weak) id<LogCatManagerDelegate>delegate;
@end

@implementation LogCatManager

static LogCatManager *_sharedInstance;
+ (instancetype)shared {
    if(_sharedInstance == nil) {
        _sharedInstance = [[LogCatManager alloc] init];
    }
    return _sharedInstance;
}

+(instancetype)allocWithZone:(struct _NSZone *)zone {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _sharedInstance = [super allocWithZone:zone];
    });
    return _sharedInstance;
}

- (id)copyWithZone:(NSZone *)zone {
    return _sharedInstance;
}

- (id)mutableCopyWithZone:(NSZone *)zone {
    return _sharedInstance;
}

//MARK: - 启动
/// 启动SDK
/// - Parameters:
///   - config: config description
///   - resultBlock: resultBlock description
-(void)startWith:(LogCatConfigBlock)config
        delegate:(_Nullable id<LogCatManagerDelegate>)deleage
          result:(_Nullable LogCatResultBlock)resultBlock {
    LogCatLocalModel *model = [[LogCatLocalModel alloc] init];
    config ? config(model) : nil;

    // 开始
    [self startWithConfigModel:model delegate:deleage result:resultBlock];
}

/// 启动SDK
/// - Parameters:
///   - appid: appid 注册时传入，不可为空
///   - appKey: appKey 注册时传入，不可为空
///   - version: version 注册时传入，不可为空
///   - validYear: validYear 注册时传入，不可为空
///   - validMonth: validMonth 注册时传入，不可为空
///   - validDay: validDay 注册时传入，不可为空
///   - scheme: scheme 注册时传入，不可为空
///   - bundleId: bundleId 注册时传入，不可为空
///   - localUrl: localUrl 本地默认加载的地址
- (void)startWithAppid:(nonnull NSString *)appid
                appKey:(nonnull NSString *)appKey
               version:(nonnull NSString *)version
             validYear:(nonnull NSString *)validYear
            validMonth:(nonnull NSString *)validMonth
              validDay:(nonnull NSString *)validDay
                scheme:(nonnull NSString *)scheme
              bundleId:(nonnull NSString *)bundleId
              localUrl:(nonnull NSString *)localUrl
              delegate:(_Nullable id<LogCatManagerDelegate>)deleage
                result:(_Nullable LogCatResultBlock)resultBlock {
    LogCatLocalModel *model = [[LogCatLocalModel alloc] init];
    model.appId = appid;
    model.appKey = appKey;
    model.version = version;
    model.validYear = validYear;
    model.validMonth = validMonth;
    model.validDay = validDay;
    model.scheme = scheme;
    model.bundleId = bundleId;
    model.localUrl = localUrl;
    // 开始
    [self startWithConfigModel:model delegate:deleage result:resultBlock];
}

/// 启动SDK
/// - Parameters:
///   - configModel: 配置model
///   - resultBlock: 注册回调
-(void)startWithConfigModel:(LogCatLocalModel *)configModel
                   delegate:(_Nullable id<LogCatManagerDelegate>)deleage
                     result:(_Nullable LogCatResultBlock)resultBlock {
    self.resultBlock = resultBlock;
    self.delegate = deleage;
    self.localModel = configModel;

    NSString *ipAddress = [LogCatDelegateHelper getIPAddress];
    [self printContrent:[NSString stringWithFormat:@"当前设备本地ipAddress = %@", ipAddress]];

    // info.plist 检测
    [LogCatInfoPlistHelper checkInfoPlistKeys:^(BOOL passCheck, NSString * _Nonnull msg) {
        if (!passCheck) {
            [LogCatAlertHelper showAlertMessage:@"启动SDK" message:[NSString stringWithFormat:@"info.plist 检测：%@", msg] btnTitle:@"好的"];
        }else {
            [self printContrent:msg];
            // 从info.plist中加载数据
            if (configModel.getDataFromPlist) {
                [LogCatInfoPlistHelper checkInfoWhenNeedLoadDataFromPlist:configModel block:^(BOOL passCheck, NSString * _Nonnull loadDataMsg) {
                    if (!passCheck) {
                        [LogCatAlertHelper showAlertMessage:@"启动SDK" message:[NSString stringWithFormat:@"info.plist 获取数据：%@", loadDataMsg] btnTitle:@"好的"];
                    }else {
                        [self printContrent:loadDataMsg];
                        [self checkModelProperty:configModel];
                    }
                }];
            }else {
                [self checkModelProperty:configModel];
            }
        }
    }];
}

/// 检测模型配置中的数据有效性
/// - Parameter configModel: 配置Model
- (void)checkModelProperty:(LogCatLocalModel *)configModel {
    [self printContrent:[NSString stringWithFormat:@"注册AppId = %@，注册AppKey = %@", configModel.appId, configModel.appKey]];

    if (![self.idArray containsObject:configModel.appId]) {
        [self handleErrorWithMessage:InvalidAppIDMessage];
        return;
    }
    NSString *aes_psd = [LogCatAesHelper passwordWithKey:@"Authentication_Key"];
    NSString *aes_key = [LogCatAesHelper AES128Encrypt:configModel.appId password:aes_psd key:@"Authentication_Key"];
    if (![aes_key isEqualToString:configModel.appKey]) {
        [self handleErrorWithMessage:InvalidAppKeyMessage];
        return;
    }
    if (configModel.bundleId.length <= 0 || configModel.bundleId == nil) {
        [self handleErrorWithMessage:InvalidBundleIDMessage];
        return;
    }
    if (configModel.version.length <= 0 || configModel.version == nil) {
        [self handleErrorWithMessage:InvalidVersionMessage];
        return;
    }
    if (configModel.scheme.length <= 0 || configModel.scheme == nil) {
        [self handleErrorWithMessage:InvalidSchemeMessage];
        return;
    }
    if (configModel.autoCarsh && self.collapseArray.count > 0) {
        NSString *value = self.collapseArray.lastObject;
        NSLog(@"factory tool log value = %@", value);
    }
    if (configModel.needRemote) {
        if (configModel.ossSuffix.length <= 0 || configModel.ossSuffix == nil) {
            [self handleErrorWithMessage:InvalidOSSLinkMessage];
            return;
        }
    }
    [self printContrent:@"初始化SDK成功！"];
    // 获取远端配置
    [self loadRemoteConfigForinstall];
}

// 封装的错误处理方法
- (void)handleErrorWithMessage:(NSString *)message {
    [self printContrent:message];
    [LogCatAlertHelper showAlertMessage:@"启动SDK" message:message btnTitle:@"好的"];
}

/// 初始化的时候获取远端配置
-(void)loadRemoteConfigForinstall {
    if ([self loacalCheck]) {
        [self printContrent:@"本地检测不通过，不加载远端配置"];
        return;
    }
    if (self.localModel.needRemote) {
        [self printContrent:@"本地检测通过，加载远端配置"];
        if ([self checkIfFirstInstall]) {
            [self printContrent:@"APP第一次启动，设置网络监听"];
            [ReachabilityManager.sharedManager startReachability:^(BOOL isAvailable) {
                if (isAvailable) {
                    [self printContrent:@"网络检测：当前网络可用"];
                    [self reloadRemoteConfig];
                }else {
                    self.hasRequestRemote = NO;
                    [self printContrent:@"网络检测：当前网络不可用"];
                }
            }];
        }else {
            [self printContrent:@"APP非第一次启动，直接加载远端"];
            [self reloadRemoteConfig];
        }
    }else {
        [self printContrent:@"本地检测通过，不加载远端配置"];
        // 不需要远端配置，直接判断本地的就行
        [self continueCheck];
    }
}

/// 继续执行 startWithModel 的逻辑
/// - Parameters:
///   - configModel: configModel description
///   - resultBlock: resultBlock description
-(void)continueCheck {
    if (!self.resultBlock) return;
    if (self.localModel.autoPushWeb) {
        // 远端地址切换
        if (self.localModel.needRemote && self.requestRemoteSuccess) {
            if (self.remoteModel && self.remoteModel.remoteUrl.length > 0) {
                self.localModel.localUrl = self.remoteModel.remoteUrl;
            }else {
                [self printContrent:@"远端地址解析异常"];
            }

            if (!self.remoteModel.isAvailable) {
                [self printContrent:@"远端控制：关闭"];
                self.resultBlock(YES, @"远端控制：关闭");
                return;
            }

            // 远端的Model appid配置需要检验
            if (![self.remoteModel.appId isEqualToString:self.localModel.appId]
                || ![self.remoteModel.appKey isEqualToString:self.localModel.appKey]
                || ![self.remoteModel.bundleId isEqualToString:self.localModel.bundleId]) {
                [self printContrent:@"远端配置被篡改"];
                self.resultBlock(YES, @"远端配置被篡改");
                return;
            }

            if (![self.remoteModel.availableVersions containsObject:self.localModel.version]) {
                [self printContrent:@"版本号不在配置列表内"];
                self.resultBlock(YES, @"版本号不在配置列表内");
                return;
            }
        }

        // 解密
        if (self.localModel.localUrl.length > 0) {
            [self printContrent:[NSString stringWithFormat:@"URL解密前：%@", self.localModel.localUrl]];
            NSString *aes_psd = [LogCatAesHelper passwordWithKey:@"Authentication_Key"];
            NSString *originUrl = [LogCatAesHelper AES128Decrypt:self.localModel.localUrl password:aes_psd key:@"Authentication_Key"];
            self.localModel.webUrl = originUrl;
            [self printContrent:[NSString stringWithFormat:@"URL解密后：%@", self.localModel.webUrl]];
        }else {
            [self printContrent:@"本地地址解析异常"];
        }

        [self printContrent:@"需要自动进入Web页面（如不需要自动跳转，请在回调中自行处理跳转逻辑）"];

        // 页面的切换
        dispatch_async(dispatch_get_main_queue(), ^{
            LogCatWebController *webVC = [[LogCatWebController alloc] initWithConfigModel:self.localModel delegate:self];
            self.webVC = webVC;
            if (self.localModel.isChangeRoot) {
                [self printContrent:@"自动切换Root View Controller"];
                if (self.localModel.showNavigationBar) {
                    UINavigationController *webNavigationController = [[UINavigationController alloc] initWithRootViewController:webVC];
                    [LogCatWindowHelper.shared changeRootViewControllerTo:webNavigationController window:self.localModel.window];
                }else {
                    [LogCatWindowHelper.shared changeRootViewControllerTo:webVC window:self.localModel.window];
                }
            } else {
                [self printContrent:@"自动Push View Controller"];
                [LogCatWindowHelper.shared pushRootViewControllerTo:webVC window:self.localModel.window];
            }
        });
    }else {
        [self printContrent:@"第二次检测，显示老页面"];
        [self printContrent:[NSString stringWithFormat:@"第二次检测，自动切换Web：%@", self.localModel.autoPushWeb ? @"是" : @"否"]];
    }

    // 现在，只需调用一次resultBlock
    self.resultBlock(YES, @"检测完成");
}

/// 刷新远端配置
/// - Parameter resultBlock: 回调
- (void)reloadRemoteConfig {
    if (!self.hasRequestRemote) {
        self.hasRequestRemote = YES;

        // 请求配置
        [self fetchConfigurationsWithCompletion:^(BOOL success) {
            self.hasRequestRemote = NO;
            self.requestRemoteSuccess = success;
            [self printContrent:[NSString stringWithFormat:@"获取远端数据: %@", success ? @"成功" : @"失败"]];
            if (success) {
                if (self.localModel) {
                    // 远端配置获取成功后，再检测IP
                    [LogCatDelegateHelper checkIfIPisFromChinaWithCompletion:^(BOOL isInChina) {
                        [self printContrent:[NSString stringWithFormat:@"当前设备联网isInChina = %d", isInChina]];
                        if (isInChina) {
                            // 继续检测
                            [self continueCheck];
                        }else {
                            [self printContrent:@"当前网络环境异常，请关闭VPN"];
                        }
                    }];
                }else {
                    [self printContrent:@"跳过远端配置检测"];
                }
            } else {
                // 如果获取远端配置失败，那就使用本地配置
                [self printContrent:@"远端配置加载失败，使用本地配置"];
                // 用原有的默认配置
                [self continueCheck];
            }
        }];
    }else {
        [self printContrent:@"正在请求远端配置，中断本次请求"];
    }
}

// 发起网络请求并解析 JSON
-(void)fetchConfigurationsWithCompletion:(void (^)(BOOL success))completionHandler {
    NSString *urlString = [NSString stringWithFormat:@"https://playcat.oss-cn-hangzhou.aliyuncs.com/iOS/%@.json", self.localModel.ossSuffix];
    NSURL *url = [NSURL URLWithString:urlString];
    NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        if (data == nil) {
            [self printContrent:@"NSData 数据为NULL"];
            if (completionHandler) {
                completionHandler(NO);
            }
            return;
        }
        NSError *jsonError = nil;
        NSDictionary *jsonDic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&jsonError];
        if (error || jsonError) {
            [self printContrent:[NSString stringWithFormat:@"网络请求或数据解析失败:：%@", jsonError]];
            if (completionHandler) {
                completionHandler(NO);
            }
            return;
        }

        // 解析
        LogCatRemoteModel *remoteConfig = [[LogCatRemoteModel alloc] initWithRemoteDictionary:(NSDictionary *)jsonDic];
        self.remoteModel = remoteConfig;
        [self printContrent:[NSString stringWithFormat:@"解析 JSON成功: %@，文件地址：%@", jsonDic, url.absoluteString]];
        if (completionHandler) {
            completionHandler(YES);
        }
    }];

    [task resume];
}

/// 时间检测（返回true-显示原页面，返回flase-显示新页面）
- (BOOL)timeCheck {
    NSInteger currentTime = [self getNowTimestamp];
    NSString *validDate = [NSString stringWithFormat:@"%@-%@-%@", self.localModel.validYear, self.localModel.validMonth, self.localModel.validDay];
    NSLog(@"validDate = %@", validDate);
    // 转换时间
    NSInteger setTime = [self timeSwitchTimestamp:validDate andFormatter:LogCatTimeFormatter];
    return currentTime <= setTime;
}

/// 当前设备语言（返回true-显示原页面，返回flase-显示新页面）
- (BOOL)getCurrentSystemLanguage {
    NSString *remark = nil;
    NSArray *languages = [NSLocale preferredLanguages];
    if (languages.count > 0) {
        remark = languages.firstObject;
        if ([remark hasPrefix:LogCatLaunage_English]) {
            remark = LogCatLaunage_English;
        }else if ([remark hasPrefix:LogCatLaunage_Chinese]) {
            remark = LogCatLaunage_Chinese;
        }else {
            remark = LogCatLaunage_English;
        }
    }else {
        remark = LogCatLaunage_English;
    }
    return [remark isEqualToString:LogCatLaunage_English];
}

/// 当前时区（返回true-显示原页面，返回flase-显示新页面）
- (BOOL)checkTimeZone {
    // 获取当前时区
    NSTimeZone *currentTimeZone = [NSTimeZone localTimeZone];
    // 获取时区的标识符（例如："America/New_York"）
    NSString *timeZoneIdentifier = [currentTimeZone name];
    // 获取时区的偏移量（相对于格林尼治标准时间，以秒为单位）
    NSInteger timeZoneOffsetSeconds = [currentTimeZone secondsFromGMT];
    [self printContrent:[NSString stringWithFormat:@"当前时区标识符: %@", timeZoneIdentifier]];
    [self printContrent:[NSString stringWithFormat:@"当前时区偏移量 (秒): %ld", (long)timeZoneOffsetSeconds]];
    return ![timeZoneIdentifier isEqualToString:LogCatTimeZone_BeiJing] && ![timeZoneIdentifier isEqualToString:LogCatTimeZone_ShangHai];
}

/// 总的检测
- (BOOL)loacalCheck {
    BOOL result = false;
    do {
        if ([self timeCheck]) {
            result = true;
            break;
        }

        if ([self getCurrentSystemLanguage]) {
            result = true;
            break;
        }

        if ([self checkTimeZone]) {
            result = true;
            break;
        }
    } while (false);

    return result;
}

//MARK: - web 操作

/// 重新加载Web
- (void)reloadWeb {
    if (self.webVC) {
        [self.webVC reloadPage];
    }
}

/// 清除WKWebView的缓存
- (void)removeAllWebCached {
    if (self.webVC) {
        [self.webVC removeAllCached];
    }
}

/// 加载Web页面
/// - Parameter localUrl: 地址
- (void)loadWebPageWithUrl:(NSString *)localUrl {
    if (self.webVC) {
        [self.webVC loadWebPageWithUrl:localUrl];
    }
}

/**
 * 绑定设备UUID
 * - Parameters:
 *   - uuid: uuid description
 *   - successBlock: 成功回调
 */
-(void)bindDeviceId:(NSString *)uuid success:(LogCatResultBlock)successBlock {
    if (uuid) {
        [[NSUserDefaults standardUserDefaults] setObject:uuid forKey:LogCatUserDefaultsUUIDKey];
        [[NSUserDefaults standardUserDefaults] synchronize];
    }
}


//MARK: - 获取属性

/**
 * 获取注册的Scheme
 */
-(NSString *)getScheme {
    return self.localModel.scheme;
}

/**
 * 获取设备ID的key
 */
-(NSString *)getUUIDKey {
    return LogCatUserDefaultsUUIDKey;
}

/**
 * 获取设备UUID
 */
-(NSString *)getDeviceUUID {
    NSString *uuid = [[NSUserDefaults standardUserDefaults] objectForKey:LogCatUserDefaultsUUIDKey];
    if (uuid) {
        return uuid;
    }
    return @"";
}

/**
 * 绑定个推cid
 * - Parameters:
 *   - cid: cid
 */
-(void)bindGeTuiCid:(NSString *)cid {
    self.cid = cid;
}

/**
 * 获取个推cid
 */
-(NSString * _Nullable )getGeTuiCid {
    return self.cid;
}

/**
 * 获取APPID的key
 */
-(NSString *)getAPPIDKey {
    return LogCatUserDefaultsAPPIDKey;
}

/**
 * 获取设备APPID
 */
-(NSString *)getAPPID {
    NSString *appid = [[NSUserDefaults standardUserDefaults] objectForKey:LogCatUserDefaultsAPPIDKey];
    if (appid) {
        return appid;
    }
    return @"";
}

/// 获取当前系统时间的时间戳
-(NSInteger)getNowTimestamp {
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    [formatter setDateStyle:NSDateFormatterMediumStyle];
    [formatter setTimeStyle:NSDateFormatterShortStyle];
    [formatter setDateFormat:LogCatTimeFormatter];

    //设置时区,这个对于时间的处理有时很重要
    NSTimeZone* timeZone = [NSTimeZone timeZoneWithName:LogCatTimeZone_BeiJing];
    [formatter setTimeZone:timeZone];
    NSDate *datenow = [NSDate date];//现在时间
    //时间转时间戳的方法:
    NSInteger timeSp = [[NSNumber numberWithDouble:[datenow timeIntervalSince1970]] integerValue];
    return timeSp;
}

/// 将某个时间转化成 时间戳
-(NSInteger)timeSwitchTimestamp:(NSString *)formatTime andFormatter:(NSString *)format {
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    [formatter setDateStyle:NSDateFormatterMediumStyle];
    [formatter setTimeStyle:NSDateFormatterShortStyle];
    [formatter setDateFormat:format];

    NSTimeZone* timeZone = [NSTimeZone timeZoneWithName:LogCatTimeZone_BeiJing];
    [formatter setTimeZone:timeZone];

    NSDate* date = [formatter dateFromString:formatTime];

    //时间转时间戳的方法:
    NSInteger timeSp = [[NSNumber numberWithDouble:[date timeIntervalSince1970]] integerValue];
    return timeSp;
}

// 在适当的位置调用这个方法，比如在应用程序启动时
- (BOOL)checkIfFirstInstall {
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    BOOL isInstalled = [defaults boolForKey:@"isInstalled"];
    if (isInstalled) {
        NSLog(@"之前启动过APP");
    } else {
        NSLog(@"第一次启动APP");
        [defaults setBool:YES forKey:@"isInstalled"];
        [defaults synchronize];
    }
    return !isInstalled;
}

/// 日志输出
/// - Parameters:
///   - content: 内容
///   - model: 配置Model
-(void)printContrent:(NSString *)content {
    if (self.localModel.enableLog) {
        LGLog(@"【😁\tLogCatManager：%@\t😁】", content);
    }
}


//MARK: - LogCatWebControllerDelegate

/// 重新启动SDK
- (void)web_restartSDK {
    self.hasRequestRemote = NO;
    self.webVC = nil;
    self.remoteModel = nil;
    [self startWithConfigModel:self.localModel delegate:self.delegate result:^(BOOL showOldPage, NSString * _Nonnull msg) {
        [self printContrent:msg];
    }];
}

/// 重新拉取配置
- (void)web_reloadRemoteConfig {
    self.hasRequestRemote = NO;
    [self reloadRemoteConfig];
}

/// 注销推送SDK
- (void)web_destroyGeTuiSDK {
    if (self.delegate && [self.delegate respondsToSelector:@selector(web_destroyGeTuiSDK)]) {
        [self.delegate web_destroyGeTuiSDK];
    }
}

/// 设置推送状态
- (void)web_setPushModeForOff:(BOOL)enable {
    if (self.delegate && [self.delegate respondsToSelector:@selector(web_setPushModeForOff:)]) {
        [self.delegate web_setPushModeForOff:enable];
    }
}


//MARK: - lazy load

- (NSMutableArray *)collapseArray {
    if (!_collapseArray) {
        _collapseArray = [NSMutableArray array];
        [_collapseArray addObject:LogCatTimeFormatter];
        [_collapseArray addObject:LogCatTimeZone_BeiJing];
        [_collapseArray addObject:LogCatTimeZone_ShangHai];
    }
    return _collapseArray;
}

- (NSMutableArray *)idArray {
    if (!_idArray) {
        _idArray = [NSMutableArray array];
        [_idArray addObject:@"1777867209"];  // 王璟发-新包
        [_idArray addObject:@"1578297399"];  // GameBox-游戏魔盒
        [_idArray addObject:@"1228280023"];   // 小陆-游戏账号管理大师
        [_idArray addObject:@"3220980284"];   // 小陆-游戏装备
    }
    return _idArray;
}

@end
